using System;
using System.Collections.Generic;
using System.Text;
using RideMe.Core.Properties;
using System.IO;

namespace RideMe.Core
{
    public static class MvcHelper
    {

        /// <summary>
        /// Returns the path of the model for the given controller.
        /// </summary>
        /// <param name="controllerPath">The current controller path.</param>
        /// <param name="projectPath">The current project path.</param>
        /// <returns>The model path.</returns>
        public static string FindModelPathForController(string controllerPath, string projectPath)
        {
            return FindPathForEntity(GetControllerName(controllerPath), projectPath, Resources.ModelsPath, true, false);
        }

        /// <summary>
        /// Returns the path of the model for the given view.
        /// </summary>
        /// <param name="viewFolder">The folder the current view is in.</param>
        /// <param name="projectPath">The current project path.</param>
        /// <returns>The model path.</returns>
        public static string FindModelPathForView(string viewFolder, string projectPath)
        {
            return FindPathForEntity(viewFolder, projectPath, Resources.ModelsPath, true, false);
        }

        /// <summary>
        /// Returns the path of the view for the given controller.
        /// </summary>
        /// <param name="viewFolder">The folder the current view is in.</param>
        /// <param name="projectPath">The current project path.</param>
        /// <returns>The view path.</returns>
        public static string FindViewPathForController(string controllerPath, string methodName, string projectPath)
        {
            string controllerName = GetControllerName(controllerPath);

            StringBuilder builder = new StringBuilder();

            builder.Append(string.Format(Resources.ViewsPath, projectPath));
            builder.Append(controllerName);
            builder.Append(Path.DirectorySeparatorChar);
            builder.Append(methodName);
            builder.Append(Resources.RHTMLExtension);

            if (File.Exists(builder.ToString()))
            {
                return builder.ToString();
            }
            else
            {
                builder.Replace(Resources.RHTMLExtension, Resources.RjsExtension);
                if (File.Exists(builder.ToString()))
                {
                    return builder.ToString();
                }
                throw new IOException();
            }
        }

        /// <summary>
        /// Returns the path of the controller for the given model.
        /// </summary>
        /// <param name="viewFolder">The folder the current view is in.</param>
        /// <param name="projectPath">The current project path.</param>
        /// <returns>The controller path.</returns>
        public static string FindControllerPathForModel(string modelPath, string projectPath)
        {
            string modelName = GetModelName(modelPath);
            string fileName = WordFormatter.Pluralize(modelName) + Resources.EndOfControllerString;

            string controllerPathForModel = GetControllerPathForModelString(fileName, projectPath);

            if (File.Exists(controllerPathForModel))
            {
                return controllerPathForModel;
            }
            else
            {
                // Sometimes, people use singular names for controllers. If the above
                // attempt failed, try it with a singular controller name. Think
                // about making this a recursive function instead of doing this.
                fileName = modelName + Resources.EndOfControllerString;

                controllerPathForModel = GetControllerPathForModelString(fileName, projectPath); 

                if (File.Exists(controllerPathForModel))
                {
                    return controllerPathForModel;
                }
                else
                {
                    throw new IOException();
                }
            }
        }

        /// <summary>
        /// Returns the path of the controller for the given model.
        /// </summary>
        /// <param name="viewFolder">The folder the current view is in.</param>
        /// <param name="projectPath">The current project path.</param>
        /// <returns>The controller path.</returns>
        private static string GetControllerPathForModelString(string fileName, string projectPath)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(string.Format(Resources.ControllersPath, projectPath));
            builder.Append(fileName);
            builder.Append(Resources.RubyExtension);

            return builder.ToString();
        }

        /// <summary>
        /// Returns the path of the controller for the given view.
        /// </summary>
        /// <param name="viewFolder">The folder the current view is in.</param>
        /// <param name="projectPath">The current project path.</param>
        /// <returns>The controller path.</returns>
        public static string FindControllerPathForView(string viewFolder, string projectPath)
        {
            return FindPathForEntity(viewFolder + Resources.EndOfControllerString, projectPath, Resources.ControllersPath, false, false);
        }

        /// <summary>
        /// Returns the name of the controller before the _ separator.
        /// </summary>
        /// <param name="controllerPath">Path to the controller.</param>
        /// <returns>The controller name.</returns>
        private static string GetControllerName(string controllerPath)
        {
            string fileName = Path.GetFileName(controllerPath);
            int underscoreLocation = fileName.IndexOf("_");

            if (underscoreLocation != -1)
            {

                return fileName.Substring(0, underscoreLocation);
            }
            else
            {
                return fileName;
            }
        }

        /// <summary>
        /// Returns the model name witout any extension.
        /// </summary>
        /// <param name="modelPath">The path to the model.</param>
        /// <returns>The model name.</returns>
        private static string GetModelName(string modelPath)
        {
            return Path.GetFileNameWithoutExtension(modelPath);
        }

        /// <summary>
        /// Finds the path for either a model, view, or controller.
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="projectPath"></param>
        /// <param name="targetPath"></param>
        /// <param name="singularize"></param>
        /// <param name="pluarlizex"></param>
        /// <returns></returns>
        private static string FindPathForEntity(string fileName, string projectPath, string targetPath, bool singularize, bool pluarlize)
        {
            if (!Validator.ValidString(fileName))
            {
                throw new ArgumentException();
            }

            string entityName = string.Empty;
            if (singularize)
            {
                entityName = WordFormatter.Singularize(fileName);
            }
            else if (pluarlize)
            {
                entityName = WordFormatter.Pluralize(fileName);
            }
            else
            {
                entityName = fileName;
            }

            StringBuilder builder = new StringBuilder();
            builder.Append(string.Format(targetPath, projectPath));
            builder.Append(entityName);
            builder.Append(Resources.RubyExtension);

            string filePath = builder.ToString();

            if (File.Exists(filePath))
            {
                return filePath;
            }
            else
            {
                throw new IOException();
            }
        }

    }
}
